#include "device/ec200/AtNetworkDeviceEC200.h"

#define GSM_AT_CMD "AT" // AT测试指令

#define GSM_CPIN_CMD "AT+CPIN?" // 检查SIM卡状态
#define GSM_CPIN_RES "READY"    // SIM卡状态返回

#define GSM_PREG_CMD "AT+CGREG?"  // 获取PS网络注册状态
#define GSM_PREG_RES "+CGREG: 0," // PS网络注册返回前缀

#define GSM_PDP_CMD "AT+QIACT?"    // 获取PDP注册信息(IP地址)
#define GSM_PDP_RES "+QIACT: 1,1," // 获取IP返回前缀

#define GSM_IMEI_CMD "AT+CGSN"     // 获取IMEI
#define GSM_IMEI_RES "+CGSN\r\r\n" // 获取IMEI返回前缀

#define GSM_ICCID_CMD "AT+QCCID" // 获取ICCID
#define GSM_ICCID_RES "+QCCID: " // 获取ICCID返回前缀

#define GSM_RSSI_CMD "AT+CSQ" // 获取信号强度
#define GSM_RSSI_RES "+CSQ: " // 获取信号强度返回前缀

#define AT_CMD_PDP_ACTIVE "AT+QIACT=1"                          // 激活PDP网络上下文
#define AT_CMD_PDP_DISABLE "AT+QIDEACT=1"                       // 禁用PDP网络上下文
#define AT_CMD_PDP_CONFIG "AT+QICSGP=1,3,\"CMNET\",\"\",\"\",1" // 配置PDP网络上下文

#define GSM_WAIT_TIME() delay(500)

int8_t AtNetworkDeviceEC200::connect(uint32_t timeout_second) {
  uint32_t expire_time = millis() + timeout_second * 1000;

  // ----------------------------------------------------------
  // - 等待AT指令正常
  // ----------------------------------------------------------
  while (timeout_second > 0 && expire_time > 0) {
    this->streamWriteClear(GSM_AT_CMD GSM_NL);
    if (this->wait(AT_OK) != AT_RCODE1) {
      if (expire_time < millis()) {
        return CONNECT_ERR_1;
      }

      GSM_WAIT_TIME();

      continue;
    }

    break;
  }

  // ----------------------------------------------------------
  // - 等待SIM准备完成
  // ----------------------------------------------------------
  while (timeout_second > 0 && expire_time > 0) {
    this->streamWriteClear(GSM_CPIN_CMD GSM_NL);
    if (this->wait(GSM_CPIN_RES) != AT_RCODE1) {
      if (expire_time < millis()) {
        return CONNECT_ERR_2;
      }

      GSM_WAIT_TIME();

      continue;
    }

    break;
  }

  // ----------------------------------------------------------
  // - 等待PS网络注册完成
  // ----------------------------------------------------------
  while (timeout_second > 0 && expire_time > 0) {
    this->streamWriteClear(GSM_PREG_CMD GSM_NL);
    if (this->wait(GSM_PREG_RES) != AT_RCODE1) {
      if (expire_time < millis()) {
        return CONNECT_ERR_3;
      }

      GSM_WAIT_TIME();

      continue;
    }

    // 获取PS网络注册状态-----------------------
    int ps = this->streamGetInt(1);
    if (ps != 1 && ps != 5) {
      GSM_WAIT_TIME();

      continue;
    }

    break;
  }

  // ----------------------------------------------------------
  // - 获取设备IMEI
  // ----------------------------------------------------------
  this->streamWriteClear(GSM_IMEI_CMD GSM_NL);
  if (this->wait(GSM_IMEI_RES) == AT_RCODE1) {
    this->streamGet(this->imei, 15);
  }

  // ----------------------------------------------------------
  // - 禁用PDP网络上下文
  // ----------------------------------------------------------
  this->streamWriteClear(AT_CMD_PDP_DISABLE GSM_NL);
  if (this->wait(AT_OK) != AT_RCODE1) {
    return CONNECT_ERR_5;
  }

  // ----------------------------------------------------------
  // - 配置PDP网络上下文
  // ----------------------------------------------------------
  this->streamWriteClear(AT_CMD_PDP_CONFIG GSM_NL);
  if (this->wait(AT_OK) != AT_RCODE1) {
    return CONNECT_ERR_5;
  }

  // ----------------------------------------------------------
  // - 激活PDP网络上下文
  // ----------------------------------------------------------
  this->streamWriteClear(AT_CMD_PDP_ACTIVE GSM_NL);
  if (this->wait(10000L, AT_OK) != AT_RCODE1) {
    return CONNECT_ERR_5;
  }

  // ----------------------------------------------------------
  // - 判定联网是否成功&获取IP地址信息
  // ----------------------------------------------------------
  this->streamWriteClear(GSM_PDP_CMD GSM_NL);
  if (this->wait(GSM_PDP_RES) != AT_RCODE1) {
    return CONNECT_ERR_5;
  }

  // 获取IP地址类型(IPV4/IPV6)---------------------
  int type = this->streamGetInt(1, GSM_SEG);
  if (type == 1 && this->streamSkipUntil('\"')) {
    this->streamGet(this->ipv4, 15, '\"');
  }
  if (type == 3 && this->streamSkipUntil('\"')) {
    this->streamGet(this->ipv4, 15, '\"');
  }
  if (type == 3 && this->streamSkipUntil('\"')) {
    this->streamGet(this->ipv6, 39, '\"');
  }

  return CONNECT_SUCCESS;
}

/**
 * 获取设备固件版本
 */
String AtNetworkDeviceEC200::getDeviceVersion(uint32_t timeout) {
  this->streamWriteClear("AT+CGMR" GSM_NL);

  if (this->wait("+CGMR\r\r\n") == AT_RCODE1) {
    char result[32] = {0};

    this->streamGet(result, 32, '\r');

    return String(result);
  }

  return String("ERROR");
}

/**
 * 获取设备型号
 */
String AtNetworkDeviceEC200::getDeviceModel(uint32_t timeout) {
  this->streamWriteClear("AT+CGMM" GSM_NL);

  if (this->wait("+CGMM\r\r\n") == AT_RCODE1) {
    char result[16] = {0};

    this->streamGet(result, 16, '\r');

    return String(result);
  }

  return String("ERROR");
}

/**
 * 获取设备IMEI
 */
String AtNetworkDeviceEC200::getDeviceIMEI(uint32_t timeout) {
  this->streamWriteClear("AT+CGSN" GSM_NL);

  if (this->wait("+CGSN\r\r\n") == AT_RCODE1) {
    char result[16] = {0};

    this->streamGet(result, 16, '\r');

    return String(result);
  }

  return String("ERROR");
}

/**
 * 获取设备ICCID
 */
String AtNetworkDeviceEC200::getIccid(uint32_t timeout) {
  this->streamWriteClear("AT+QCCID" GSM_NL);

  if (this->wait("+QCCID: ") == AT_RCODE1) {
    char result[24] = {0};

    this->streamGet(result, 24, '\r');

    return String(result);
  }

  return String("ERROR");
}

/**
 * 获取设备RSSI(信号强度)
 */
int AtNetworkDeviceEC200::getRssi(uint32_t timeout) {
  this->streamWriteClear("AT+CSQ" GSM_NL);

  if (this->wait("+CSQ: ") == AT_RCODE1) {
    return this->streamGetInt(4, ',');
  }

  return 0;
}
